#pragma once

#include "GemMiner.h"
#include "Consola.h"
#include "RegistoUtensilio.h"
#include "Pedra.h"
#include "Aluminio.h"
#include "TerrenoMole.h"
#include "TerrenoDuro.h"
#include "Carvao.h"
#include "Ferro.h"
#include "Ouro.h"
#include "Diamante.h"
#include "BlocoVazio.h"
#include "VigaBloco.h"
#include "EscadaBloco.h"
#include "Picareta.h"
#include "AutoPicareta.h"
#include "MarteloPneumatico.h"
#include "Mochila.h"
#include "MochilaPro.h"
#include "MochilaHD.h"
#include "Holofote.h"
#include "Isqueiro.h"
#include "Lanterna.h"
#include "BebidaEnergetica.h"
#include "Frigorifico.h"
#include "Lancheira.h"
#include "LataAtum.h"
#include "AplicaEscada.h"
#include "AplicaViga.h"
#include <string>
#include <sstream>
#include <fstream>

using namespace std;

GemMiner::GemMiner(Interface* i)
{
	this->i = i;
	isGameCreated = false;
	isRunning = true;
	isGameOn = false;
	tabuleiroActual = NULL;
	mineiro = NULL;
	loadPriceTable("valorUtensilios.txt");
}

GemMiner::~GemMiner()
{
	delete i;
}

void GemMiner::start()
{
	while(isRunning)
	{
		//Menu principal
		while(!isGameCreated)
		{
			string comandoMenu = i->drawMenu();
			if(validaComandoMenu(comandoMenu))
			{
				if(trataComandoMenu(comandoMenu))
					exit(0);
			}
		}

		if(tabuleiroActual == NULL)
			return;

		mineiro = tabuleiroActual->getMineiro();

		isGameOn = true;

		int energia;
		int tempo;
		int numEscadas;
		int numVigas;
		int numMoedas;
		int* minerios;
		int capacidadeMochila;
		int pesoActualMochila;

		//Jogo
		while(true)
		{
			energia = mineiro->getEnergiaMineiro();
			tempo = tabuleiroActual->getTempo();
			numEscadas = tabuleiroActual->getMineiro()->getAplicaEscada()->getQuantidade();
			numVigas = tabuleiroActual->getMineiro()->getAplicaViga()->getQuantidade();
			numMoedas = tabuleiroActual->getMineiro()->getMoedas();
			minerios = tabuleiroActual->getMineiro()->getMochila()->getMinerios();
			capacidadeMochila = tabuleiroActual->getMineiro()->getMochila()->getCapacidade();
			pesoActualMochila = tabuleiroActual->getMineiro()->getMochila()->getPesoActual();

			i->paint();
			i->drawHUD(energia, tempo, numEscadas, numVigas, numMoedas, minerios, capacidadeMochila, pesoActualMochila);
			i->drawPriceTable(tabelaPrecos);
			char tecla = i->getch();
			trataEventos(tecla);
			if(isGameOn != true)
				break;
			isGameOn = tabuleiroActual->aplicaGravidade();
			if(isGameOn != true)
				break;
			//tabuleiroActual->aplicaGravidadePedra(tabuleiroActual);
		}
		i->drawGameOverScreen();
		i->getch();
		isGameCreated = false;
	}
}

//Retorna true if exit
bool GemMiner::trataComandoMenu(string comando)
{
	//jogo <nome_jogo> <num_linhas> <num_colunas> <dificuldade>
	//load <nome_jogo>
	//exit

	istringstream iss(comando);
	string auxiliar;

	iss >> auxiliar;

	if(auxiliar == "jogo")
	{
		string nome;
		int colunas;
		int linhas;
		int dificuldade;

		iss >> nome >> linhas >> colunas >> dificuldade;

		tabuleiroActual = new Tabuleiro(nome, linhas, colunas, dificuldade);
		tabuleiros.push_back(tabuleiroActual);
		isGameCreated = true;
		i->addObservable(tabuleiroActual);
		return false;
	}

	if(auxiliar == "load")
	{
		string nomeficheiro;
		iss >> nomeficheiro;

		loadPriceTable(nomeficheiro);
		return false;
	}

	if(auxiliar == "exit")
	{
		return true;
	}

	if(auxiliar == "cheat")
	{
		tabuleiroActual = new Tabuleiro("mina1.txt");
		tabuleiros.push_back(tabuleiroActual);
		isGameCreated = true;
		i->addObservable(tabuleiroActual);
		return false;
	}

	return false;
}

bool GemMiner::validaComandoMenu(string comando)
{
	//jogo <nome_jogo> <num_linhas> <num_colunas> <dificuldade>
	//load <nome_jogo>
	//exit

	int numPalavras = contaPalavras(comando);
	istringstream iss(comando);
	string auxiliar;


	if(iss.peek() != EOF)
	{
		iss >> auxiliar;

		if(auxiliar == "jogo" && numPalavras == 5)
		{
			string nome;
			int linhas;
			int colunas;
			int dificuldade;

			iss >> nome;
			iss >> linhas;
			iss >> colunas;
			iss >> dificuldade;

			if( typeid(nome).name() != typeid(string).name() || 
				typeid(linhas).name() != typeid(int).name() ||
				typeid(colunas).name() != typeid(int).name() ||
				typeid(dificuldade).name() != typeid(int).name() )

				return false;

			return true;
		}

		if(auxiliar == "load" && numPalavras == 2)
		{
			string nomeficheiro;
			iss >> nomeficheiro;

			//if(typeid(nomeficheiro).name() != "string")
			//	return false;

			return true;
		}

		if(auxiliar == "exit" && numPalavras == 1)
		{
			return true;
		}

		if(auxiliar == "cheat" && numPalavras == 1)
		{
			return true;
		}
	}
	return false;
}

bool GemMiner::trataComandoJogo(string comando)
{
	//h
	//u <nome_utensilio>
	//b <tipo> <linha coluna>
	//t <linha> <coluna>
	//g <valor>
	//e <valor>
	//c <novo_nome>
	//f <nome>
	//a
	//x
	//j

	istringstream iss(comando);
	string auxiliar;

	if(iss.peek() != EOF)
	{
		iss >> auxiliar;

		if(auxiliar == "u")
		{
			int linha = tabuleiroActual->getMineiro()->getPosicao()->getLinha();
			int moedas = tabuleiroActual->getMineiro()->getMoedas();
			Mineiro* min = tabuleiroActual->getMineiro();
			iss >> auxiliar;

			if(linha == 0)
			{

				if(auxiliar == "P")
				{
					if(moedas >= 10)
					{
						min->gastaMoedas(10);
						delete min->getPicareta();
						min->setPicareta(new Picareta());
					}
				}

				if(auxiliar == "PA")
				{
					if(moedas >= 90)
					{
						min->gastaMoedas(90);
						delete min->getPicareta();
						min->setPicareta(new AutoPicareta());
					}
				}
				if(auxiliar == "MP")
				{
					if(moedas >= 150)
					{
						min->gastaMoedas(150);
						delete min->getPicareta();
						min->setPicareta(new MarteloPneumatico());
					}
				}
				if(auxiliar == "M")
				{
					if(moedas >= 10)
					{
						min->gastaMoedas(10);
						delete min->getMochila();
						min->setMochila(new Mochila());
					}
				}
				if(auxiliar == "MPro")
				{
					if(moedas >= 75)
					{
						min->gastaMoedas(75);
						delete min->getMochila();
						min->setMochila(new MochilaPro());
					}
				}
				if(auxiliar == "MHD")
				{
					if(moedas >= 140)
					{
						min->gastaMoedas(140);
						delete min->getMochila();
						min->setMochila(new MochilaHD());
					}
				}
				if(auxiliar == "I")
				{
					if(moedas >= 10)
					{
						min->gastaMoedas(10);
						delete min->getTipoLuz();
						min->setTipoLuz(new Isqueiro());
					}
				}
				if(auxiliar == "L")
				{
					if(moedas >= 70)
					{
						min->gastaMoedas(70);
						delete min->getTipoLuz();
						min->setTipoLuz(new Lanterna());
					}
				}
				if(auxiliar == "H")
				{
					if(moedas >= 150)
					{
						min->gastaMoedas(150);
						delete min->getTipoLuz();
						min->setTipoLuz(new Holofote());
					}
				}
				if(auxiliar == "LA")
				{
					if(moedas >= 50)
					{
						min->gastaMoedas(50);
						delete min->getEnergia();
						min->setEnergia(new LataAtum());
					}
				}
				if(auxiliar == "BE")
				{
					if(moedas >= 100)
					{
						min->gastaMoedas(100);
						delete min->getEnergia();
						min->setEnergia(new BebidaEnergetica());
					}
				}
				if(auxiliar == "LC")
				{
					if(moedas >= 160)
					{
						min->gastaMoedas(160);
						delete min->getEnergia();
						min->setEnergia(new Lancheira());
					}
				}
				if(auxiliar == "FP")
				{
					if(moedas >= 320)
					{
						min->gastaMoedas(320);
						delete min->getEnergia();
						min->setEnergia(new Frigorifico());
					}
				}
				if(auxiliar == "AE")
				{
					if(moedas >= 5)
					{
						min->gastaMoedas(5);
						min->addAplicaEscada(5);
					}
				}
				if(auxiliar == "AV")
				{
					if(moedas >= 5)
					{
						min->gastaMoedas(5);
						min->addAplicaViga(5);
					}
				}
			}
			return true;
		}
		if(auxiliar == "b")
		{
			int linha;
			int coluna;
			iss >> auxiliar;
			iss >> linha;
			iss >> coluna;

			if(linha >= 0 && linha < tabuleiroActual->getAltura() && coluna >= 0 && coluna < tabuleiroActual->getLargura())
			{
				if(auxiliar == "P")
				{
					delete tabuleiroActual->getTabuleiro()[linha][coluna];
					tabuleiroActual->addBloco(new Pedra(linha, coluna), linha, coluna);
				}

				if(auxiliar == "TM")
				{
					delete tabuleiroActual->getTabuleiro()[linha][coluna];
					tabuleiroActual->addBloco(new TerrenoMole(linha, coluna), linha, coluna);
				}

				if(auxiliar == "TD")
				{
					delete tabuleiroActual->getTabuleiro()[linha][coluna];
					tabuleiroActual->addBloco(new TerrenoDuro(linha, coluna), linha, coluna);
				}

				if(auxiliar == "A")
				{
					delete tabuleiroActual->getTabuleiro()[linha][coluna];
					tabuleiroActual->addBloco(new Aluminio(linha, coluna), linha, coluna);
				}

				if(auxiliar == "C")
				{
					delete tabuleiroActual->getTabuleiro()[linha][coluna];
					tabuleiroActual->addBloco(new Carvao(linha, coluna), linha, coluna);
				}

				if(auxiliar == "F")
				{
					delete tabuleiroActual->getTabuleiro()[linha][coluna];
					tabuleiroActual->addBloco(new Ferro(linha, coluna), linha, coluna);
				}

				if(auxiliar == "O")
				{
					delete tabuleiroActual->getTabuleiro()[linha][coluna];
					tabuleiroActual->addBloco(new Ouro(linha, coluna), linha, coluna);
				}

				if(auxiliar == "D")
				{
					delete tabuleiroActual->getTabuleiro()[linha][coluna];
					tabuleiroActual->addBloco(new Diamante(linha, coluna), linha, coluna);
				}

				if(auxiliar == "E")
				{
					delete tabuleiroActual->getTabuleiro()[linha][coluna];
					tabuleiroActual->addBloco(new EscadaBloco(linha, coluna), linha, coluna);
				}

				if(auxiliar == "V")
				{
					delete tabuleiroActual->getTabuleiro()[linha][coluna];
					tabuleiroActual->addBloco(new VigaBloco(linha, coluna), linha, coluna);
				}
			}
			return true;
		}
		if(auxiliar == "t")
		{
			int linha;
			int coluna;
			iss >> linha;
			iss >> coluna;

			if(linha >= 0 && linha < tabuleiroActual->getAltura() && coluna >= 0 && coluna < tabuleiroActual->getLargura())
			{
				if(tabuleiroActual->getTabuleiro()[linha][coluna]->permiteMineiro())
				{
					mineiro->setPosicao(tabuleiroActual->getTabuleiro()[linha][coluna]);
				}
			}
			return true;
		}
		if(auxiliar == "g")
		{
			int moedas;
			iss >> moedas;

			mineiro->setMoedas(moedas);
			return true;
		}
		if(auxiliar == "e")
		{
			int vida;
			iss >> vida;

			mineiro->setEnergiaMineiro(vida);
			return true;
		}
		if(auxiliar == "c")
		{
			return true;
		}
		if(auxiliar == "f")
		{
			return true;
		}
		if(auxiliar == "a")
		{
			return true;
		}
		if(auxiliar == "x")
		{
			return false;
		}
		if(auxiliar == "j")
		{
			return true;
		}
	}
}

bool GemMiner::validaComandoJogo(string comando)
{
	//h
	//u <nome_utensilio>
	//b <tipo> <linha coluna>
	//t <linha> <coluna>
	//g <valor>
	//e <valor>
	//c <novo_nome>
	//f <nome>
	//a
	//x
	//j

	istringstream iss(comando);
	string auxiliar;

	if(iss.peek() != EOF)
	{
		iss >> auxiliar;

		if(auxiliar == "h")
		{
			return true;
		}

		if(auxiliar == "u")
		{
			try {
				string nome;
				iss >> nome;
			} catch(exception e) {
				return false;
			}
			return true;
		}

		if(auxiliar == "b")
		{
			try {
				string tipo;
				int linhas;
				int colunas;
				iss >> tipo >> linhas >> colunas;
			} catch(exception e) {
				return false;
			}
			return true;
		}

		if(auxiliar == "t")
		{
			try {
				int linhas;
				int colunas;
				iss >> linhas >> colunas;
			} catch(exception e) {
				return false;
			}
			return true;
		}

		if(auxiliar == "g")
		{
			try {
				int valor;
				iss >> valor;
			} catch(exception e) {
				return false;
			}
			return true;
		}

		if(auxiliar == "e")
		{
			try {
				int valor;
				iss >> valor;
			} catch(exception e) {
				return false;
			}
			return true;
		}

		if(auxiliar == "c")
		{
			try {
				string nome;
				iss >> nome;
			} catch(exception e) {
				return false;
			}
			return true;
		}

		if(auxiliar == "f")
		{
			try {
				string nome;
				iss >> nome;
			} catch(exception e) {
				return false;
			}
			return true;
		}

		if(auxiliar == "a")
		{
			try {
				string nome_original;
				string nome_destino;
				iss >> nome_original >> nome_destino;
			} catch(exception e) {
				return false;
			}
			return true;
		}

		if(auxiliar == "x")
		{
			isGameOn = false;
			return true;
		}

		if(auxiliar == "j")
		{
			return true;
		}
	}
	return false;
}

void GemMiner::trataEventos(char tecla)
{
	Bloco* posicaoMineiro = tabuleiroActual->getMineiro()->getPosicao();
	int linhaBloco = tabuleiroActual->getMineiro()->getPosicao()->getLinha();
	int colunaBloco = tabuleiroActual->getMineiro()->getPosicao()->getColuna();
	int forcaPicareta = tabuleiroActual->getMineiro()->getPicareta()->getForca();
	int energiaTotal = tabuleiroActual->getMineiro()->getEnergiaMineiro();
	int* minerios = tabuleiroActual->getMineiro()->getMochila()->getMinerios();
	int moedas = tabuleiroActual->getMineiro()->getMoedas();

	if(linhaBloco == 0)
	{
		tabuleiroActual->getMineiro()->setEnergia();
		tabuleiroActual->getMineiro()->setMoedas((minerios[0] * 5) + moedas);
		tabuleiroActual->getMineiro()->setMoedas((minerios[1] * 8) + moedas);
		tabuleiroActual->getMineiro()->setMoedas((minerios[2] * 12) + moedas);
		tabuleiroActual->getMineiro()->setMoedas((minerios[3] * 18) + moedas);
		tabuleiroActual->getMineiro()->setMoedas((minerios[4] * 25) + moedas);

		for(unsigned int i = 0; i < 5; i++)
		{
			minerios[i] = 0;
		}

		tabuleiroActual->getMineiro()->getMochila()->setPesoActual(0);
	}

	if(tecla == Consola::ESQUERDA)
	{
		if(colunaBloco - 1 >= 0)
		{
			Bloco* blocoEsquerda = tabuleiroActual->getTabuleiro()[linhaBloco][colunaBloco-1];
			if(blocoEsquerda->verificaVida() > 0)
			{
				blocoEsquerda->interagePicareta(forcaPicareta);

				if(blocoEsquerda->verificaVida() == 0)
				{
					if(blocoEsquerda->hasConteudo())
					{
						tabuleiroActual->getMineiro()->getMochila()->addMinerio(blocoEsquerda->getConteudo());
					}

					int x = blocoEsquerda->getLinha();
					int y = blocoEsquerda->getColuna();
					delete blocoEsquerda;
					blocoEsquerda = new BlocoVazio(x, y);
					tabuleiroActual->addBloco(blocoEsquerda, x, y);
					tabuleiroActual->getMineiro()->mover(blocoEsquerda);
					tabuleiroActual->avancaTempo();
					tabuleiroActual->getMineiro()->gastaEnergia();
					isGameOn = tabuleiroActual->verificaVida();
				}
				else
				{
					tabuleiroActual->avancaTempo();
					tabuleiroActual->getMineiro()->gastaEnergia();
					isGameOn = tabuleiroActual->verificaVida();
				}
			}
			else
			{
				tabuleiroActual->getMineiro()->mover(blocoEsquerda);
				tabuleiroActual->avancaTempo();
			}
		}
	}

	if(tecla == Consola::DIREITA)
	{
		if(colunaBloco + 1 < tabuleiroActual->getLargura())
		{
			Bloco* blocoDireita = tabuleiroActual->getTabuleiro()[linhaBloco][colunaBloco+1];
			if(blocoDireita->verificaVida() > 0)
			{
				blocoDireita->interagePicareta(forcaPicareta);

				if(blocoDireita->verificaVida() == 0)
				{
					if(blocoDireita->hasConteudo())
					{
						tabuleiroActual->getMineiro()->getMochila()->addMinerio(blocoDireita->getConteudo());
					}
					int x = blocoDireita->getLinha();
					int y = blocoDireita->getColuna();
					delete blocoDireita;
					blocoDireita = new BlocoVazio(x, y);
					tabuleiroActual->addBloco(blocoDireita, x, y);
					tabuleiroActual->getMineiro()->mover(blocoDireita);
					tabuleiroActual->avancaTempo();
					tabuleiroActual->getMineiro()->gastaEnergia();
					isGameOn = tabuleiroActual->verificaVida();
				}
				else
				{
					tabuleiroActual->avancaTempo();
					tabuleiroActual->getMineiro()->gastaEnergia();
					isGameOn = tabuleiroActual->verificaVida();
				}
			}
			else
			{
				tabuleiroActual->getMineiro()->mover(blocoDireita);
				tabuleiroActual->avancaTempo();
			}
		}
	}

	if(tecla == Consola::CIMA)
	{
		if(linhaBloco - 1 >= 0)
		{
			Bloco* blocoCima= tabuleiroActual->getTabuleiro()[linhaBloco-1][colunaBloco];
			if(blocoCima->verificaVida() > 0)
			{
				blocoCima->interagePicareta(forcaPicareta);

				if(blocoCima->verificaVida() == 0)
				{
					if(blocoCima->hasConteudo())
					{
						tabuleiroActual->getMineiro()->getMochila()->addMinerio(blocoCima->getConteudo());
					}
					int x = blocoCima->getLinha();
					int y = blocoCima->getColuna();
					delete blocoCima;
					blocoCima = new BlocoVazio(x, y);
					tabuleiroActual->addBloco(blocoCima, x, y);
					tabuleiroActual->avancaTempo();
					tabuleiroActual->getMineiro()->gastaEnergia();
					isGameOn = tabuleiroActual->verificaVida();
				}
				else
				{
					tabuleiroActual->avancaTempo();
					tabuleiroActual->getMineiro()->gastaEnergia();
					isGameOn = tabuleiroActual->verificaVida();
				}
			}
			else
			{
				if(tabuleiroActual->getMineiro()->getPosicao()->moveCima())
				{
					Bloco* blocoCima= tabuleiroActual->getTabuleiro()[linhaBloco-1][colunaBloco];
					tabuleiroActual->getMineiro()->mover(blocoCima);
					tabuleiroActual->avancaTempo();
				}
			}
		}
	}

	if(tecla == Consola::BAIXO)
	{
		if(linhaBloco + 1 < tabuleiroActual->getAltura())
		{
			Bloco* blocoBaixo = tabuleiroActual->getTabuleiro()[linhaBloco+1][colunaBloco];
			if(blocoBaixo->verificaVida() > 0)
			{
				blocoBaixo->interagePicareta(forcaPicareta);

				if(blocoBaixo->verificaVida() == 0)
				{
					if(blocoBaixo->hasConteudo())
					{
						tabuleiroActual->getMineiro()->getMochila()->addMinerio(blocoBaixo->getConteudo());
					}
					int x = blocoBaixo->getLinha();
					int y = blocoBaixo->getColuna();
					delete blocoBaixo;
					blocoBaixo = new BlocoVazio(x, y);
					tabuleiroActual->addBloco(blocoBaixo, x, y);
					tabuleiroActual->getMineiro()->mover(blocoBaixo);
					tabuleiroActual->avancaTempo();
					tabuleiroActual->getMineiro()->gastaEnergia();
					isGameOn = tabuleiroActual->verificaVida();
				}
				else
				{
					tabuleiroActual->avancaTempo();
					tabuleiroActual->getMineiro()->gastaEnergia();
					isGameOn = tabuleiroActual->verificaVida();
				}
			}
			else
			{
				tabuleiroActual->getMineiro()->mover(blocoBaixo);
				tabuleiroActual->avancaTempo();
			}
		}
	}

	if(tecla == 'v')
	{
		if(posicaoMineiro->permiteAplicar())
		{
			if(tabuleiroActual->getMineiro()->getAplicaViga()->getQuantidade() > 0)
			{
				delete posicaoMineiro;
				posicaoMineiro = new VigaBloco(linhaBloco, colunaBloco);
				tabuleiroActual->addBloco(posicaoMineiro, linhaBloco, colunaBloco);
				tabuleiroActual->getMineiro()->setPosicao(posicaoMineiro);
				tabuleiroActual->getMineiro()->gastaViga();
				tabuleiroActual->avancaTempo();
			}
		}
	}

	if(tecla == 'e')
	{
		if(posicaoMineiro->permiteAplicar())
		{
			if(tabuleiroActual->getMineiro()->getAplicaEscada()->getQuantidade() > 0)
			{
				delete posicaoMineiro;
				posicaoMineiro = new EscadaBloco(linhaBloco, colunaBloco);
				tabuleiroActual->addBloco(posicaoMineiro, linhaBloco, colunaBloco);
				tabuleiroActual->getMineiro()->setPosicao(posicaoMineiro);
				tabuleiroActual->getMineiro()->gastaEscada();
				tabuleiroActual->avancaTempo();
			}
		}
	}

	if(tecla == 'c')
	{
		string comandoJogo = i->drawCommandLine();
		if(validaComandoJogo(comandoJogo))
		{
			if(trataComandoJogo(comandoJogo))
				return;
		}
	}
}

void GemMiner::saveGame()
{

}

int GemMiner::contaPalavras(const string& palavra)
{
	stringstream stream(palavra);
	return distance(istream_iterator<string>(stream), istream_iterator<string>());
}

void GemMiner::loadPriceTable(string nomeficheiro)
{
	ifstream ifs("valorUtensilios.txt");
	int id;
	int preco;

	if (ifs.is_open())
	{
		while(ifs != NULL)
		{
			ifs >> id;
			ifs >> preco;

			tabelaPrecos.push_back(new RegistoUtensilio(id, preco));
		}
	}
}